﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.BusinessData.Runtime;
using System.ComponentModel;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System.Net;
using System.IO;
using System.Diagnostics;

namespace TFSCustomConnector
{
    public partial class TFSHelper
    {
        static string token = "123";
        static string Identifier = "System123Id";
        static string WIWASLink = "WI123Hyperlink";
        
        static void Log2Server(string source, string message)
        {
            string clsNamespace = "???";
            string wiType = "???";
            string spSiteURL = "???";

            StringBuilder soapRequest = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            soapRequest.Append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">");
            soapRequest.Append("<soap:Body>");
            soapRequest.Append("<SendClientScriptErrorReport xmlns=\"http://schemas.microsoft.com/sharepoint/diagnostics/\">");
            soapRequest.Append("<message>" + message + "</message>");
            soapRequest.Append("<file>"+source+"</file>");
            soapRequest.Append("<line></line>");
            soapRequest.Append("<client>" + wiType + "</client>");
            soapRequest.Append("<stack></stack>");
            soapRequest.Append("<team>" + clsNamespace + "</team>");
            soapRequest.Append("<originalFile></originalFile>");
            soapRequest.Append("</SendClientScriptErrorReport>");
            soapRequest.Append("</soap:Body>");
            soapRequest.Append("</soap:Envelope>");

            WebRequest webRequest = WebRequest.Create(spSiteURL + "/_vti_bin/Diagnostics.asmx");
            HttpWebRequest httpRequest = (HttpWebRequest)webRequest;
            httpRequest.Method = "POST";
            httpRequest.ContentType = "text/xml; charset=utf-8";
            httpRequest.Accept = "text/xml";
            httpRequest.ContentLength = soapRequest.Length;
            httpRequest.Headers.Add("SOAPAction: http://schemas.microsoft.com/sharepoint/diagnostics/SendClientScriptErrorReport");
            httpRequest.ProtocolVersion = HttpVersion.Version11;
            httpRequest.Credentials = CredentialCache.DefaultCredentials;

            using (Stream requestStream = httpRequest.GetRequestStream())
            {
                //Create Stream and Complete Request             
                StreamWriter streamWriter = new StreamWriter(requestStream, Encoding.ASCII);
                streamWriter.Write(soapRequest.ToString());
                streamWriter.Close();
            }
            
            //Get the Response    
            using (HttpWebResponse wr = (HttpWebResponse)httpRequest.GetResponse())
            {
                StreamReader srd = new StreamReader(wr.GetResponseStream());
                srd.ReadToEnd();
                srd.Close();
            }
        }

        static string Log(string source, string message, string clsNamespace, string wiType)
        {
            string formattedmessage = string.Format("LobSystem: {0}, Entity: {1}, Source: {2}, Message: {3}",clsNamespace, wiType, source, message);

            if (!EventLog.SourceExists(clsNamespace))
                EventLog.CreateEventSource(clsNamespace, "Application");

            var flag = (source.Contains("error") ? EventLogEntryType.Error : EventLogEntryType.Information);

            EventLog.WriteEntry(clsNamespace, formattedmessage, flag);

            return formattedmessage;
        }

        static DynamicType FillDynamicItem(DynamicType template, WorkItem wi, string clsNamespace, string wiType, string TfsConnURL)
        {
            var newDynamicItem = new DynamicType();
            var strBld = new StringBuilder();
            string res;
            strBld.Length = 0;

            foreach (var itm in template)
            {
                if (itm.Key.Equals(Identifier))
                {
                    newDynamicItem.Add(Identifier, wi.Id);
                }
                else if (itm.Key.Equals(WIWASLink))
                {
                    string ptojguid = wi.Project.Uri.AbsolutePath;
                    string url = TfsConnURL.Substring(0, TfsConnURL.LastIndexOf('/')) + "/web/UI/Pages/WorkItems/WorkItemEdit.aspx?id=" + wi.Id + "&pguid=" + ptojguid.Substring(ptojguid.LastIndexOf('/')+1);
                    newDynamicItem.Add(WIWASLink, url + ", " + wi.Title);
                }
                else
                {
                    object fld = null;
                    try
                    {                  
                        fld = wi[itm.Key.Replace(token,".")];
                    }
                    catch(Exception ex)
                    {
                        res = Log("FillDynamicItem error", "wi.Id=" + wi.Id + ", itm.Key=" + itm.Key, clsNamespace, wiType);
                        strBld.AppendLine(res);
                        res = Log("FillDynamicItem error", ex.ToString(), clsNamespace, wiType);
                        strBld.AppendLine(res);

                        newDynamicItem.Add(itm.Key, null);
                        continue;
                    }

                    //Log("FillDynamicItem", itm.Key + "=" + fld, clsNamespace, wiType);
                    if (fld is DateTime && ((DateTime)fld).Year == 9999)
                        newDynamicItem.Add(itm.Key, null);
                    else
                        newDynamicItem.Add(itm.Key, fld);
                }
            }

            if(strBld.Length > 0) throw new Exception(strBld.ToString());

            return newDynamicItem;
        }

        static void UpdateWorkItem(DynamicType dynamicItem, WorkItem wi, string clsNamespace, string wiType)
        {
            object origField;

            wi.Open();
            foreach (var itm in dynamicItem.Where(x => x.Key != Identifier))
            {
                //Log("UpdateWorkItem", itm.Key + "=" + (string)itm.Value, clsNamespace, wiType);
                var fld = wi.Fields[itm.Key.Replace(token, ".")];

                if (itm.Value == null || !fld.IsEditable || fld.IsComputed) continue;

                origField = fld.Value;
                try
                {
                    fld.Value = itm.Value;
                }
                catch(Exception ex)
                {
                    Log("UpdateWorkItem error - field cannot be set", ex.ToString(), clsNamespace, wiType);
                    fld.Value = origField;
                }

                if (fld.Status != FieldStatus.Valid)
                {
                    Log("UpdateWorkItem error - FieldStatus is invalid", itm.Key + "=" + fld.Status.ToString(), clsNamespace, wiType);
                    fld.Value = origField;
                }
            }

            if (!wi.IsValid())
            {
                var strBld = new StringBuilder();
                var errors = wi.Validate();
                foreach (Field fld in errors)
                {
                    string mess = Log("UpdateWorkItem errors - invalid fields", "Field=" + fld.Name + ", Reason=" + fld.Status.ToString() + ", Value=" + fld.Value, clsNamespace, wiType);
                    strBld.AppendLine(mess);
                }
                wi.Reset();
                wi.Close();

                throw new Exception(strBld.ToString());
            }
            else 
                wi.Save();

            wi.Close();
        }

        static WorkItemStore ConnectToTFS(string TFSConnectionURL, string clsNamespace, string wiType)
        {
            TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri(TFSConnectionURL));
            var wistore = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));

            //Log("ConnectToTFS", TFSConnectionURL, clsNamespace, wiType);
            if (wistore == null) throw new Exception("wistore == null");

            return wistore;
        }

        internal static void DestroyWorkItem(string TfsConnURL, int ID, string clsNamespace, string wiType)
        {
            //Log("DestroyWorkItem", ID.ToString(), clsNamespace, wiType);

            WorkItemStore wistore = ConnectToTFS(TfsConnURL, clsNamespace, wiType);
            var errors = wistore.DestroyWorkItems(new int[] { ID });

            var strBld = new StringBuilder();
            bool isError = false;
            foreach (var err in errors)
            {
                var res = Log("DestroyWorkItem errors", err.Exception.ToString(), clsNamespace, wiType);
                strBld.AppendLine(res);
                isError = true;
            }

            if (isError) throw new Exception(strBld.ToString());
        }

        internal static DynamicType FindWorkItem(string TfsConnURL, int ID, DynamicType template, string clsNamespace, string wiType)
        {
            WorkItemStore wistore = ConnectToTFS(TfsConnURL, clsNamespace, wiType);
            var wi = wistore.GetWorkItem(ID);
            //Log("FindWorkItem", ID.ToString(), clsNamespace, wiType);

            return FillDynamicItem(template, wi, clsNamespace, wiType, TfsConnURL);
        }

        internal static void UpdateWorkItem(string TfsConnURL, DynamicType dynamicItem, string clsNamespace, string wiType)
        {
            WorkItemStore wistore = ConnectToTFS(TfsConnURL, clsNamespace, wiType);

            int ID = (int)dynamicItem[Identifier];
            var wi = wistore.GetWorkItem(ID);
            //Log("UpdateWorkItem", ID.ToString(), clsNamespace, wiType);

            UpdateWorkItem(dynamicItem, wi, clsNamespace, wiType);
        }

        internal static int CreateWorkItem(string TfsConnURL, DynamicType template, string witype, string TfsProject, string clsNamespace, string wiType)
        {
            WorkItemStore wistore = ConnectToTFS(TfsConnURL, clsNamespace, wiType);
            var prj = wistore.Projects[TfsProject];
            var witfields = prj.WorkItemTypes[witype];
            var wi = witfields.NewWorkItem();

            //Log("CreateWorkItem", wi.Id.ToString(), clsNamespace, wiType);

            UpdateWorkItem(template, wi, clsNamespace, wiType);

            return wi.Id;
        }

        internal static DynamicType[] QueryWorkItems(string TfsConnURL, string filter, DynamicType template, string clsNamespace, string wiType)
        {
            var dynItemColl = new List<DynamicType>();

            WorkItemStore wistore = ConnectToTFS(TfsConnURL, clsNamespace, wiType);
            var wicoll = wistore.Query(filter);
            //Log("QueryWorkItems", wicoll.Count + "==>" + filter, clsNamespace, wiType);

            foreach(WorkItem wi in wicoll)
            {
                //Log("QueryWorkItems", wi.Id.ToString(), clsNamespace, wiType);
                dynItemColl.Add(FillDynamicItem(template, wi, clsNamespace, wiType, TfsConnURL));
            }

            return dynItemColl.ToArray();
        }
    }
}
